Controlling the 3.5 Drive Hardware on the Apple IIGS
By Neil Parker
Copyright (c) 1991 Apple Users' Group, Sydney
Republished from Applecations, a publication of the Apple Users' Group, Sydney, Australia.


A real live working program!

The program listed below was written to illustrate the steps necessary to control the hardware of the 3.5 Drive from your own programs, without the use of the operating system or the firmware. It is essentially a 3.5-inch version of the DUMP program by Don Worth which was printed in _Beneath_Apple_DOS_. It will read a track from a 3.5-inch disk into your Apple's memory, in its raw, encoded form.

Included below are a commented source code listing and a hex dump suitable for typing directly into the System Monitor (or capturing into a text file and EXECing).

Instructions:

First, boot DOS 3.3 or ProDOS 8. DUMP3.5 should be compatible with either operating system. If you booted ProDOS, get into BASIC.SYSTEM. When you see the ] prompt, type "BLOAD DUMP3.5", and then "CALL-151". Store the number of the track you wish to examine in memory location 6, and the disk side you wish to examine (0 for the lower side, anything else for the upper side) in location 7. Put the disk to be examined in Drive 1, and type "900G". The raw track data will then be found in memory locations $1000 through $7FFF (this buffer is much longer than an actual track, so the data will most likely be repeated several times in the buffer).

For example,

]BLOAD DUMP3.5      (Load the program)
]CALL-151           (Enter the Monitor)
*6:20               (Select track $20)
*7:1                (Select upper side)
*900G               (Run DUMP3.5 (don't forget to insert the disk first))
*1000.10FF          (Examine the first 256 bytes of the track)

The usual Dire Warnings apply: I make no guarantees whatsoever for this program. I have tested it, and it seems to work on mycomputer, but I recommend using it ONLY on expendable disks, and ONLY with the write-protect hole open. I assume no responsibility for any damage which may result from the use or misuse of this program.

Be especially careful if you enter either the assembly listing or the hex dump by hand--the slightest typographical error could turn a benign tool into a malevolent disk-eating monster.

I hope this program helps clarify the disk access process. If there is enough interest in an explanation of how to interpret what it accesses, it might be possible to talk me into writing up an explanation of the block encoding process. (I recommend first reading "Beneath Apple DOS" (if you can find a copy), and also the SmartPort chapter of the Firmware Reference.)

;*********************************************************** **************
; DUMP3.5--Dump a track of a 3.5-inch disk to memory.  (IIGS only)
;
; By Neil Parker--inspired by Don Worth's DUMP program from "Beneath
; Apple DOS"
;
; Inputs: $06 = Track to be dumped
;         $07 = Side to be dumped (0=lower side, non-0=upper side)
; Outputs: $1000-$7FFF = raw track data
;
; Example:
;     *6:20 1      (Select track $20, upper side)
;     *900G        (Run DUMP3.5)
;     *1000.10FF   (Examine part of the track)
;*********************************************************** **************
       ORG $900
TRACK     EQU 6           ;Track number
SIDE      EQU 7           ;Side number
PTR       EQU 8
BUFFER    EQU $1000       ;Start address for track data
SLTROMSEL EQU $C02D       ;Select internal/external ROMs for slots
DISKREG   EQU $C031       ;Select 3.5/5.25 drive, control SEL line
CYAREG    EQU $C036       ;System speed and motor-on-detect bits
CA0       EQU $C0E0       ;Phase 0, 3.5 drive control
CA1       EQU $C0E2       ;Phase 1, 3.5 drive control
CA2       EQU $C0E4       ;Phase 2, 3.5 drive control
LSTRB     EQU $C0E6       ;Phase 3, control strobe
ENABLE    EQU $C0E8       ;Turn drive off/on
SELECT    EQU $C0EA       ;Select drive 1/2
Q6        EQU $C0EC
Q7        EQU $C0EE
;
          LDA SLTROMSEL   ;Get slot 6 status,
          PHA             ;save it,
          AND #$BF        ;force internal ROM+I/O for Slot 6
          STA SLTROMSEL
          LDA CA0         ;Clear disk I/O latches
          LDA CA1
          LDA CA2
          LDA LSTRB
          LDA ENABLE      ;Insure that drive is off
          LDA SELECT      ;Select drive 1
          LDA Q6          ;Set IWM for reading (a "safe" state)
          LDA Q7
          LDA #$F         ;Configure IWM for 3.5 access
          JSR SELIWM
          LDA DISKREG     ;Save old DISKREG
          PHA
          ORA #$40        ;Select 3.5 drive
          STA DISKREG
          LDA ENABLE+1    ;Turn drive on
          LDA #2          ;Is there a disk in the drive?
          JSR SEL35
          JSR TEST35
          BPL THERE       ;If so, read
          JMP DONE        ;otherwise quit
THERE     LDA #8          ;Turn motor on
          JSR SEL35
          JSR TRIG35
          LDA #1          ;Set step direction=outward
          JSR SEL35
          JSR TRIG35
TSTTRK0   LDA #$A         ;Are we at track 0 yet?
          JSR SEL35
          JSR TEST35
          BPL ATTRK0      ;If so, go read
          LDA #4          ;otherwise do a step
          JSR SEL35
          JSR TRIG35
SEEKING0  JSR TEST35      ;Step still in progress?
          BPL SEEKING0    ;If so, loop until step done
          BMI TSTTRK0     ;otherwise go see if we're at track 0 yet
ATTRK0    LDX TRACK       ;What track did the user want?
          BEQ DUMP        ;If track 0, we're already there--go read
          LDA #0          ;else set step direction=inward
          JSR SEL35
          JSR TRIG35
SEEK      LDA #4          ;Do a step
          JSR SEL35
          JSR TRIG35
SEEKING   JSR TEST35      ;Step still in progress?
          BPL SEEKING     ;If so, loop until step done
          DEX             ;otherwise see if we've stepped enough yet
          BNE SEEK        ;If not, go step again
DUMP      LDA #$B         ;Disk ready for reading yet?
          JSR SEL35
READYT    JSR TEST35
          BMI READYT      ;Loop until disk ready
          LDA SIDE        ;What side did the user want?
          BEQ SIDE1       ;If 0, set lower side
          LDA #3          ;else set upper side
          BNE SETSIDE
SIDE1     LDA #1
SETSIDE   JSR SEL35
          JSR TEST35
          PHP             ;Save interrupt status
          SEI             ;Don't let anything interrupt us
          LDA CYAREG      ;Save old system speed
          PHA
          AND #$FB        ;Set speed=fast
          ORA #$80
          STA CYAREG
          LDA #<BUFFER    ;Initialize read buffer
          STA PTR         ;(NOTE:  For DOS TOOL KIT or EDASM assembler,
          LDA #>BUFFER    ;change #> to #< and #< to #>.)
          STA PTR+1
          LDY #0
DUMPLP    LDA Q6          ;Read a byte
          BPL DUMPLP      ;Loop until we have a valid byte
          STA (PTR),Y     ;Store byte in buffer
          INC PTR         ;Advance buffer pointer
          BNE DUMPLP
          INC PTR+1
          LDA PTR+1       ;Buffer full yet?
          CMP #$80
          BCC DUMPLP      ;If not, go read some more
          PLA             ;Done.  Restore system speed
          STA CYAREG
          PLP             ;Restore interrupt status
          LDA #9          ;Turn motor off
          JSR SEL35
          JSR TRIG35
DONE      LDA ENABLE      ;Turn drive off
          LDA CA0         ;Clear disk I/O latches
          LDA CA1
          LDA CA2
          LDA LSTRB
          PLA             ;Restore old DISKREG value
          STA DISKREG
       LDA #0          ;Configure IWM for 5.25 access
          JSR SELIWM
          PLA             ;Restore original slot configuration
          STA SLTROMSEL
          RTS             ;Amen.
;
;Subroutine to select 3.5 drive status/control registers
;Enter with accumulator=desired status:
;     Bit 0=CA2 status
;     Bit 1=SEL status
;     Bit 2=CA0 status
;     Bit 3=CA1 status
;
SEL35     BIT CA0
          BIT CA1+1
          BIT LSTRB
          BIT CA2
          LSR             ;If bit 0 set, turn on CA2
          BCC S35A
          BIT CA2+1
S35A      LSR             ;If bit 1 set, turn on SEL
          PHA
          LDA DISKREG
          AND #$7F
          BCC S35B
          ORA #$80
S35B      STA DISKREG
          PLA
          LSR             ;If bit 2 set, turn on CA0
          BCC S35C
          BIT CA0+1
S35C      LSR             ;If bit 3 set, turn on CA1
          BCS S35D
          BIT CA1
S35D      RTS
;
;Subroutine to read the status of the 3.5 drive
;First call SEL35 to select register to examine
;Result is in processor N (negative) flag
;
TEST35    BIT Q6+1
          BIT Q7
          RTS
;
;Subroutine to perform a 3.5 drive control function
;First call SEL35 to select function to be performed
;
TRIG35    BIT LSTRB+1
          BIT LSTRB
          RTS
;
;Subroutine to configure the IWM chip
;Before calling, make sure drive is OFF!
;Call with accumulator=desired Mode Register value
;     A=$00 for 5.25 drive
;     A=$0F for 3.5 drive
;
SELIWM    TAY
          BIT Q6+1        ;Prepare to access Mode & Status Regs.
          JMP SELIWM2     ;First see if it's already set like we want it
SELIWM1   TYA
          STA Q7+1        ;Try writing to Mode Reg.
SELIWM2   TYA
          EOR Q7          ;Compare input to Status Reg.
          AND #$1F
          BNE SELIWM1     ;If not the same, try writing again
          BIT Q6          ;else prepare IWM for data
          RTS

Here is the hext dump corresponding to the above assembler listing.
This can be entered by hand into the Monitor, or you can capture it into
a text file, put "CALL-151" at the beginning and "3D0G" and "BSAVE
DUMP3.5,A$900,L$145" at the end and EXEC it to create the program.

900:AD 2D C0 48 29 BF 8D 2D C0 AD E0 C0 AD E2 C0 AD
910:E4 C0 AD E6 C0 AD E8 C0 AD EA C0 AD EC C0 AD EE
920:C0 A9 0F 20 2E 0A AD 31 C0 48 09 40 8D 31 C0 AD
930:E9 C0 A9 02 20 F2 09 20 20 0A 10 03 4C D5 09 A9
940:08 20 F2 09 20 27 0A A9 01 20 F2 09 20 27 0A A9
950:0A 20 F2 09 20 20 0A 10 0F A9 04 20 F2 09 20 27
960:0A 20 20 0A 10 FB 30 E7 A6 06 F0 18 A9 00 20 F2
970:09 20 27 0A A9 04 20 F2 09 20 27 0A 20 20 0A 10
980:FB CA D0 F0 A9 0B 20 F2 09 20 20 0A 30 FB A5 07
990:F0 04 A9 03 D0 02 A9 01 20 F2 09 20 20 0A 08 78
9A0:AD 36 C0 48 29 FB 09 80 8D 36 C0 A9 00 85 08 A9
9B0:10 85 09 A0 00 AD EC C0 10 FB 91 08 E6 08 D0 F5
9C0:E6 09 A5 09 C9 80 90 ED 68 8D 36 C0 28 A9 09 20
9D0:F2 09 20 27 0A AD E8 C0 AD E0 C0 AD E2 C0 AD E4
9E0:C0 AD E6 C0 68 8D 31 C0 A9 00 20 2E 0A 68 8D 2D
9F0:C0 60 2C E0 C0 2C E3 C0 2C E6 C0 2C E4 C0 4A 90
A00:03 2C E5 C0 4A 48 AD 31 C0 29 7F 90 02 09 80 8D
A10:31 C0 68 4A 90 03 2C E1 C0 4A B0 03 2C E2 C0 60
A20:2C ED C0 2C EE C0 60 2C E7 C0 2C E6 C0 60 A8 2C
A30:ED C0 4C 39 0A 98 8D EF C0 98 4D EE C0 29 1F D0
A40:F4 2C EC C0 60


THIS CONTENT COPYRIGHT © 2007, APPLE MACINTOSH USERS' GROUP, SYDNEY
Permission has been obtained to make this material available on the Internet.

Permission is hereby granted for non-profit user groups to republish this content.
PLEASE CREDIT THE AUTHOR AND THE SOURCE: Applecations, publication of the Apple Users' Group, Sydney, Australia

THIS PAGE COPYRIGHT © 2007, ANDREW ROUGHAN